<template>
    <div class="app-popup" v-dragMove="getIsDragMove">
        <component :is="getPopupComp" v-bind="getBindValues">
            <template v-if="getPopupComp === 'Drawer'" #extra>
                <template v-if="$slots.extra"><slot name="extra"></slot></template>
                <template v-else>
                    <div class="ant-drawer-cust-close" @click="closePopup"><CloseOutlined /></div>
                </template>
            </template>

            <a-spin :spinning="loading"><slot name="content"></slot></a-spin>

            <template #footer>
                <a-space v-if="$slots.footer"><slot name="footer"></slot></a-space>
                <a-space v-else>
                    <a-button :loading="loading" v-bind="getProps?.cancelButtonProps" @click="handleCancelButton">{{ getProps?.cancelButtonProps?.text }}</a-button>
                    <a-button :loading="loading" v-bind="getProps?.confrimButtonProps" @click="getProps?.confrimButton">{{ getProps?.confrimButtonProps?.text }}</a-button>
                </a-space>
            </template>
        </component>
    </div>
</template>

<script lang="ts">
import type { PopupProps, CancelButtonProps, ConfrimButtonProps } from './types/popup';
import { propTypes } from '@/utils/propTypes';
import { Drawer, Modal } from 'ant-design-vue';
import { deepMerge } from '@/utils';
import { CloseOutlined } from '@ant-design/icons-vue';
import { isNumber, isFunction } from '@/utils/is';

export default defineComponent({
    name: 'popup',
    components: { Drawer, Modal, CloseOutlined },
    emits: ['register', 'before-close'],
    props: {
        type: propTypes.oneOf(['Drawer', 'Modal']).def('Drawer'), // 弹出层类型
        open: propTypes.bool.def(false),
        width: {
            type: Number || String,
            default: 800,
        },
        loading: propTypes.bool.def(false),
        styleType: String,
        confrimButton: Function as PropType<Fn>,
        cancelButton: Function as PropType<Fn>,
        confrimButtonProps: {
            type: Object as PropType<ConfrimButtonProps>,
            default: {
                text: '保存',
                type: 'primary',
                size: 'middle',
            },
        }, 
        cancelButtonProps: {
            type: Object as PropType<CancelButtonProps>,
            default: {
                text: '取消',
                size: 'middle',
            },
        }, 
    },
    setup (props, { emit, attrs }) {

        const propsRef = ref<Partial<PopupProps>>({}); // props传递参数对象

        const isMobile = inject('isMobile', ref(false)); // 判断是否手机端

        // 获取props传递的数据
        const getProps = computed(() => Object.assign({}, attrs, props, unref(propsRef)) as Recordable);

        const getPopupComp = computed(() => unref(getProps).type); // 渲染的组件

        const compWidth = computed(() => {
            let width = unref(getProps).width; if (isNumber(width)) return `${width}px`;
            return width;
        });

        const popupVisible = ref<boolean>(props.open); // 弹出层显示隐藏值

        const openPopup = () => popupVisible.value = true;

        const closePopup = () => {
            emit('before-close');
            setTimeout(() => popupVisible.value = false, 200);
        };

        const handleCancelButton = () => {
            const { cancelButton } = unref(getProps);

            if(isFunction(cancelButton)){
                cancelButton();
            }else {
                closePopup();
            }
        };

        const loading = ref<boolean>(props.loading); // 加载绑定值

        const openPopupLoading = () => loading.value = true;

        const closePopupLoading = () => loading.value = false;

        // 写入props传递的数据
        async function setProps(popupProps: Partial<PopupProps>): Promise<void> {
            propsRef.value = deepMerge(unref(propsRef), popupProps);
            popupVisible.value = popupProps?.open ? popupProps?.open : false;
            loading.value = popupProps?.loading ? popupProps?.loading : false;
        }

        // 处理组件上绑定属性值
        const getBindValues = computed(() => {
            const { type, styleType } = unref(getProps);
            if(type === 'Drawer'){
                return {
                    destroyOnClose: true,
                    footerStyle: { textAlign: 'right' },
                    ...unref(getProps),
                    open: popupVisible.value,
                    closable: false,
                    width: !unref(isMobile) ? unref(compWidth) : '100%',
                    rootClassName: styleType ? `popup-drawer popup-${styleType}` : 'popup-drawer',
                    onClose: closePopup,
                }
            }else{
                return { 
                    destroyOnClose: true,
                    bodyStyle: { 'max-height': 'calc(100vh - 280px)', 'overflow-y': 'auto' },
                    centered: true,
                    ...unref(getProps),
                    open: popupVisible.value,
                    width: !unref(isMobile) ? unref(compWidth) : '95%',
                    wrapClassName: styleType ? `popup-modal popup-${styleType}` : 'popup-modal',
                    onCancel: closePopup,
                }
            }
        });

        // 获取是否允许拖拽
        const getIsDragMove = computed(() => {
            const { type } = unref(getProps);
            if(type === 'Modal'){
                return { visible: popupVisible.value, DragWrapDow: '.popup-modal' }
            }
            return {};
        });

        // 抛出到外部调用操作方法
        const popupAct = {
            setProps,
            openPopup,
            closePopup,
            openPopupLoading,
            closePopupLoading,
            loading,
        };

        onMounted(() => {
            emit('register', popupAct);
        });

        return {
            getPopupComp,
            getBindValues,
            getIsDragMove,
            ...popupAct,
            loading,
            getProps,
            handleCancelButton,
        }
    },
})
</script>

<style lang="less">
@import './popup.less';
</style>